package com.avensen.plc;

import cn.hutool.core.io.BufferUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.ValidateObjectInputStream;
import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.socket.nio.NioServer;
import sun.awt.image.IntegerInterleavedRaster;
import sun.rmi.runtime.Log;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class TestPLCServer {

    public static void main(String[] args) {

//        NioServer server = new NioServer(32769);
        NioServer server = new NioServer(60003);
        server.setChannelHandler((sc) -> {
            ByteBuffer readBuffer = ByteBuffer.allocate(1024);
            try {
                // 从channel读数据到缓冲区
                int readBytes = sc.read(readBuffer);
                if (readBytes > 0) {
                    // Flips this buffer.  The limit is set to the current position and then
                    // the position is set to z
                    //  qq
                    //  o，就是表示要从起始位置开始读取数据
                    readBuffer.flip();
                    // eturns the number of elements between the current position and the  limit.
                    // 要读取的字节长度6
                    byte[] bytes = new byte[readBuffer.remaining()];
                    // 将缓冲区的数据读到bytes数组
                    readBuffer.get(bytes);
                    String body = StrUtil.utf8Str(bytes).trim();
                    System.out.println("[" + sc.getRemoteAddress() + "]: " + body);
                    String readPattern = "%01#RDD[0-9]+\\*\\*";
                    String writePattern = "%01#WDD[0-9A-F]+\\*\\*";
                    String readRPattern = "%01#RCSR[0-9A-F]+\\*\\*"; //读R区
                    String writeRPattern = "%01#WCSR[0-9A-F]+\\*\\*"; //写R区
                    boolean isMatchReadDTRegionPattern = ReUtil.isMatch(readPattern, body);
                    boolean isMatchReadRRegionPattern = ReUtil.isMatch(readRPattern, body);
                    boolean iswriteRRegionPattern = ReUtil.isMatch(writeRPattern, body);
                    //读命令
                    if (isMatchReadDTRegionPattern) {
                        System.out.println("to read.....");
                        doWrite(sc, readAddrss(body));
                    } else if(isMatchReadRRegionPattern) {
                        System.out.println("to read. 读R区....");
                        doWrite(sc, readRCSRAddrss(body));
                    } else  if(iswriteRRegionPattern){
                        writeWCSRAddrss(body);
                        doWrite(sc, "%01$WD13");
                    }  else{
                        boolean isMatchWrite = ReUtil.isMatch(writePattern, body);
                        if (isMatchWrite) {
                            System.out.println("to write.....");
                            writeAddrss(body);
                            doWrite(sc, "%01$WD13");

                        }
                    }
                } else if (readBytes < 0) {
                    IoUtil.close(sc);
                }
            } catch (IOException e) {
                throw new IORuntimeException(e);
            }
        });
        server.listen();
    }

    public static String readRCSRAddrss(String body) {
        String keysStr = StrUtil.subBetween(body, "%01#RCSR", "**");
        if (StrUtil.isNotEmpty(keysStr)) {
            //读命令
            String[] keyAttr = StrUtil.split(keysStr, 4);
            String startAddr = keyAttr[0];
            String endAddr = keyAttr.length >1 ? keyAttr[1] : startAddr;
            StringBuffer respond = new StringBuffer("%01$RC");
            //暂时读单个寄存器
            String key = "PLCSW:R" + startAddr;
            String hexStr = CustomJedis.getHexStringForOneByte(key);
            respond.append(hexStr);
            respond.append("21");
            System.out.println("respond --> " + respond.toString());
            return respond.toString();
        }
        return null;
    }
    public static String readAddrss(String body) {
        String keysStr = StrUtil.subBetween(body, "%01#RDD", "**");
        if (StrUtil.isNotEmpty(keysStr)) {
            //读命令
            String[] keyAttr = StrUtil.split(keysStr, 5);
            Integer startAddr = Integer.valueOf(keyAttr[0]);
            Integer endAddr = Integer.valueOf(keyAttr[1]);
            StringBuffer respond = new StringBuffer("%01$RD");
            for (int i = startAddr; i <= endAddr; i++) {
                String key = "PLCSW:DT" + i;
                String hexStr = CustomJedis.getHexString(key);
                respond.append(hexStr);
            }
            respond.append("17");
            System.out.println("respond --> " + respond.toString());
            return respond.toString();
        }
        return null;
    }
    public static void writeAddrss(String body) throws Exception {
        String writeStr = StrUtil.subBetween(body, "%01#WDD", "**");
        if (StrUtil.isNotEmpty(writeStr)) {
            String[] keysArray = StrUtil.split(writeStr.substring(0, 10), 5);
            String[] vaulesArray = StrUtil.split(writeStr.substring(10), 4);
            int startAddr = Integer.valueOf(keysArray[0]);
            int endAddr = Integer.valueOf(keysArray[1]);
            if (startAddr == endAddr) { // 写单字
                //值转换
                String value = singleTransform(vaulesArray[0]);
                String key = "PLCSW:DT" + startAddr;
                System.out.println("key:"+key+", value:"+value);
                CustomJedis.getInstance().set(key, value);
            } else { // 写多字

            }
        }
    }
    public static void writeWCSRAddrss(String body) throws Exception {
        String writeStr = StrUtil.subBetween(body, "%01#WCSR", "**");
        if (StrUtil.isNotEmpty(writeStr)) {
            String key = writeStr.substring(0, 4);
            String keyValue = writeStr.substring(4, 5);
            System.out.println("key:"+key+",value:"+keyValue);
            String startAddr = key;
            { // 写单字
                //值转换
//                keyValue = String.format("%8s", keyValue).replace(' ', '0');
                System.out.println("keyvalue:"+ keyValue);
                String redisKey = "PLCSW:R" + startAddr;
                System.out.println("key:"+redisKey+", value:"+keyValue);
                CustomJedis.getInstance().set(redisKey, keyValue);
            }
        }
    }
    private static String singleTransform(String value) {
        value += "0000";
        byte[] bytes = HexUtil.decodeHex(value);
        int v = ByteUtil.bytesToInt(bytes);
        return v + "";
    }

    public static void doWrite(SocketChannel channel, String response) throws IOException {
//        String path = "/Users/luoshiwei/idea_workspace/avensen/PX211-Server/src/test/java/test/plc/resp.txt";
//        String line = FileUtil.readString(path, CharsetUtil.UTF_8);
        // 将缓冲数据写入渠道，返回给客户端
        channel.write(BufferUtil.createUtf8(response));
    }

    public static Integer getSingleByteValue(String hexStr) {
        Integer value = HexUtil.hexToInt(hexStr) >> 8 & 0xff;
        return value;
    }
}
